home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
276-300
/
283
/
bref
/
bref.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-14
|
21KB
|
814 lines
/* bref - AmigaBASIC cross referencer */
char Version[6] = "V 1.01"; /* November 3, 1989
** This program reads standard input OR one or more files
** and prints the file(s) with line numbers added plus an
** alphabetic list of word references by line number.
**
** To run:
** bref [-Q] [-Lnnn] [-Wnnn] [-Hccc] [-?] [-S] [-K] [-E] [file...]
**
** Where 'file' must be ASCII, not binary -- AmigaBasic default.
** To save a Basic program in ASCII, enter in Basic output window:
** SAVE "prog.name",A
**
** Options--first letter can be upper or lower case:
** -Q - don't print normal input file listing (Quiet).
** -Lnnn - set page Length to n instead of the default 66.
** -Wnnn - set page Width to n instead of the default 80.
** Maximum permitted page width is 132.
** -Hccc - set page Heading to 'ccc' rather than file names.
** -S - Suppress form feeds; use for screen output
** -K - show BASIC Keywords in crossref table
** -E - print the input file 12 chars/in (Elite). Default 10 cpi.
** -? - display this list.
**
** Compiled with Manx Aztec C:
** cc bref.c
** ln bref.o -lc
**
**--------------------------------------------------------------------
** Program bref is a modification of cref, the C cross referencer
**
** History -- cref and bref
** May 1981 Mike Edmonds wrote cref, a cross ref for C language
** Sept 1987 Joel Swank ported cref to the Amiga
** 1989 Dick Taylor modified cref to produce bref for BASIC
**
** Dick Taylor Found a bug?
** 99 Valley View Rd Want a program change?
** Glastonbury CT 06033 USA Editorial remarks?
** Tel (203) 633-0100 Your comments are welcome!!!
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <exec/types.h>
#include <stat.h>
#define MAXWORD 15 /* maximum chars in word */
#define MAXPAGLINES 999 /* maximum posible lines in page */
#define MINPAGLINES 4 /* minimum posible lines in page */
#define MAXLINWIDTH 132 /* maximum posible chars in line */
#define MINLINWIDTH MAXWORD+12 /* minimum posible chars in line */
#define MAXTABSIZE 132 /* maximum posible chars in tab */
#define MINTABSIZE 1 /* minimum posible chars in tab */
#define igncase(c) (isupper(c)? tolower(c) : (c))
#undef FALSE
#undef TRUE
#define FALSE 0
#define TRUE 1
#ifdef DEBUG
#define debug(a,b) fprintf(stderr,(a),(b))
#else
#define debug(a,b)
#endif
/* global structures*/
#define LINLIST struct _linlist
#define WRDLIST struct _wrdlist
struct _linlist { /* line number list node */
long ln_no ; /* line number */
LINLIST *ln_next ; /* next element pointer (or NULL) */
} ;
struct _wrdlist { /* word list node */
char *wd_wd ; /* pointer to word */
char *wd_lwd ; /* pointer to word (lower case) */
LINLIST wd_ln ; /* first element of line list */
WRDLIST *wd_low ; /* lower child */
WRDLIST *wd_hi ; /* higher child */
} ;
/* options*/
char *Progname ;
int Quiet = FALSE ; /* don't print input file listing? (-q) */
int Maxpaglines = 66 ; /* maximum lines in page (-l) */
int Maxlinwidth = 80 ; /* default chars in print line (-w) */
int Tabsize = 8 ; /* default length of tab */
int FormFeed = TRUE; /* Suppress form feeds? (-S) */
int ShowKeyWords = FALSE; /* Show BASIC keywords in table? (-K)*/
int Elite = FALSE; /* Print source code in elite? (-E) */
/* global variables*/
char Brefhdr[MAXLINWIDTH+1] ;/* report header */
char *Filename ; /* name of current input file */
char Date[30] ; /* current or last file modify date */
long Hiline = 1L ; /* current (and max.) input file line number */
int files=0 ; /* count of source files */
WRDLIST *Wdtree = NULL ; /* ptr to root node of binary word list */
int SkipToEOL = FALSE; /* Skip to EOL for REM, DATA */
int SaveMLW; /* Save Max line width */
/* AmigaBASIC language reserved keywords */
/* Entered in binary search order. This minimizes recursion */
/* during store of the keywords in the tree, thereby conserving on */
/* Stack usage. If the keywords are entered in alphabetic order, it */
/* causes a system crash (exceed Stack) during keyword store in the*/
/* tree. There are 202 keywords in this list. */
char *Bkeywords[] = {
/* Level 1 -- #101 */ "MOUSE",
/* Level 2 -- #50 & #151 */ "EOF", "RESUME",
/* Level 3 -- #25 75 126 177 */ "COLOR", "INT", "OPTION", "SUB",
/* Level 4 */
"BREAK", "DECLARE", "FRE","LOF","OBJECT.PLANES","POKEW","SIN","UCASE$",
/* Level 5 */
"AREAFILL", "CINT", "CVD", "DEFSTR", "EXIT", "IF", "LIBRARY", "MERGE",
"OBJECT.AY","OBJECT.VY", "PEEK", "PTAB","SADD","STATIC","TIME$","WEND",
/* Level 6 */
"AND", "ATN", "CHAIN", "CLNG", "COS", "CVS", "DEFINT", "EDIT",
"ERL", "FILES", "GOSUB", "INPUT", "LEFT$", "LLIST", "LPRINT", "MKI$",
"NEXT", "OBJECT.HIT", "OBJECT.START", "OCT$", "PAINT", "POINT","PRINT",
"READ", "RND", "SCREEN", "SPACE$", "STOP", "TAB", "TRANSLATE$",
"VARPTR", "WINDOW",
/* Level 7 */
"ABS", "APPEND", "AS", "BASE", "CALL", "CHDIR","CIRCLE","CLS","COMMON",
"CSNG", "CVI", "DATA", "DEF", "DEFLNG", "DELETE", "ELSEIF", "EQV",
"ERR", "EXP", "FIX", "FUNCTION", "GOTO", "IMP", "INPUT$",
"KILL", "LEN", "LINE", "LOC", "LOG", "LSET", "MID$", "MKS$", "NAME",
"NOT", "OBJECT.CLIP", "OBJECT.OFF", "OBJECT.PRIORITY", "OBJECT.STOP",
"OBJECT.X", "ON", "OR", "PALETTE", "PEEKL", "POKE", "POS", "PRINT#",
"PUT", "RESET", "RETURN", "RSET", "SAVE", "SGN", "SLEEP", "SPC",
"STEP", "STRIG", "SWAP", "TAN", "TIMER", "TRON", "USING",
"WAIT", "WHILE", "WRITE#",
/* Level 8 -- everything else */
"ALL", "AREA", "ASC", "BEEP", "CDBL", "CHR$", "CLEAR", "CLOSE",
"COLLISION", "CONT", "CSRLIN", "CVL", "DATE$", "DEFDBL", "DEFSNG",
"DIM","ELSE", "END", "ERASE", "ERROR", "FIELD", "FOR", "GET", "HEX$",
"INKEY$", "INPUT$", "INSTR", "LBOUND", "LET", "LIST", "LOAD",
"LOCATE", "LPOS", "MENU", "MKD$", "MKL$", "MOD", "NEW","OBJECT.AX",
"OBJECT.CLOSE", "OBJECT.ON", "OBJECT.SHAPE", "OBJECT.VX",
"OBJECT.Y", "OFF", "OPEN", "OUTPUT", "PATTERN", "PEEKW", "POKEL",
"PRESET", "PSET", "RANDOMIZE", "REM", "RESTORE", "RIGHT$", "RUN","SAY",
"SCROLL", "SHARED", "SOUND", "SQR", "STICK", "STR$", "STRING$",
"SYSTEM", "THEN","TO", "TROFF", "UBOUND", "VAL", "WAVE", "WIDTH",
"WRITE", "XOR",
0
} ;
/* main - Store Basic keywords in tree.
* Get program options and format heading lines.
* Get words/line numbers from input file(s), store in tree.
* Retrieve and print words in alphabetic order. For each
* word, print line numbers where word appears. */
main(argc, argv)
int argc ;
char *argv[] ;
{
char wordfilebuf[BUFSIZ] ;
register FILE *filep ;
char *getword(), *word ;
struct stat stbuf ;
long time() ;
register cnt ;
Progname = *argv ; /* get options */
getcmd(argc, argv) ;
/* If the BASIC keywords are bypassed for the output */
/* table, then store keywords in the tree with */
/* line count = 0. */
if (!ShowKeyWords)
for (cnt=0 ; Bkeywords[cnt] ; cnt++)
storword(Bkeywords[cnt], 0L) ;
listchr(-2); /* clear output line */
/* read and store files */
for (cnt=1 ; cnt < argc ; cnt++)
if (*argv[cnt] != '-')
{ files++ ;
Filename = argv[cnt] ;
if ((filep = fopen(Filename, "r")) == NULL)
fatal("can't open %s", Filename) ;
stat(Filename, &stbuf) ;
mkdate((long)stbuf.st_mtime) ;
while (word = getword(filep))
{ storword(word, Hiline);
if (strcmp(word,"REM") == 0 ||
strcmp(word,"DATA") == 0)
SkipToEOL = TRUE;
}
fclose(filep) ;
}
if (!files) /* no files - read stdin */
{ if (*Brefhdr)
Filename = Brefhdr ;
else
Filename = "stdin" ;
mkdate(time( (long *)0)) ;
while (word = getword(stdin))
storword(word, Hiline) ;
}
/* print cross reference report */
bref(Wdtree) ;
exit(0) ;
}
/* getcmd - get arguments from command line & build page headings*/
getcmd(argc, argv)
register argc ;
register char *argv[] ;
{
register cnt ;
debug("GETCMD(%d", argc) ;
debug(", %s)\n", argv[0]) ;
*Brefhdr = '\0' ;
/* get command options */
for (cnt=1; cnt < argc; cnt++)
{ if (*argv[cnt] == '-')
{ switch(igncase(argv[cnt][1]))
{ case 'q':
Quiet = TRUE ;
break ;
case 'l':
Maxpaglines = atoi(&argv[cnt][2]) ;
if (Maxpaglines < MINPAGLINES
|| Maxpaglines > MAXPAGLINES)
fatal("Bad -l value: %s", argv[cnt]) ;
break ;
case 'w':
Maxlinwidth = atoi(&argv[cnt][2]) ;
if (Maxlinwidth < MINLINWIDTH
|| Maxlinwidth > MAXLINWIDTH)
fatal("Bad -w value: %s", argv[cnt]) ;
break ;
case 's':
FormFeed = FALSE; /* Suppress form feeds */
break;
case 'k':
ShowKeyWords = TRUE; /* Show BASIC keywords */
break;
case 'e':
Elite = TRUE;
printf ("%s", "w"); /* Send elite code to printer*/
break;
case 'h':
strncpy(Brefhdr, &argv[cnt][2], MAXLINWIDTH) ;
Brefhdr[MAXLINWIDTH] = '\0' ;
break ;
case '?': /* help option */
usage();
printf(" Options--1st letter either upper or lower case:\n\n");
printf(" -Q - don't print input file listing (Quiet)\n");
printf(" -Lnnn - set page Length to n, not default 66.\n");
printf(" -Wnnn - set page Width to n, not default 80.\n");
printf(" -Hccc - set page Heading 'ccc', not file names\n");
printf(" -S - Suppress form feeds; use--screen output\n");
printf(" -K - show BASIC Keywords in CrossRef table\n");
printf(" -E - print input file 12 chars/inch (Elite)\n");
printf(" -? - display this list.\n");
exit(0);
default:
usage();
exit(0);
}
}
}
if (Elite)
{ SaveMLW = Maxlinwidth; /* Save Max Line Width */
Maxlinwidth = (Maxlinwidth * 6) / 5; /* New Max Line Width*/
}
/* insert file names in hdr */
if (!*Brefhdr)
for (cnt=1; cnt < argc; cnt++)
if (*argv[cnt] != '-')
strjoin(Brefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
}
usage()
{
printf("usage:\n\n");
printf("bref [-Q] [-Lnnn] [-Wnnn] [-Hheading] [-S] [-K] [-E] \
[-?] [file ...]\n\n");
}
/* getword - read, print and return next word from file*/
char *
getword(filep)
FILE *filep ;
{ static int first_read = TRUE;
static char wordbuf[MAXWORD+1] ;
register char *wp = wordbuf ;
register maxw = sizeof(wordbuf) ;
register chr ;
int inword=0, lastchr=0 ;
long slineno ;
#define _listchr(chr) if (!Quiet) listchr(chr)
#define _rtrnwrd(wp) \
{ ungetc(chr, filep) ; \
*(wp) = '\0' ; \
return wordbuf ; \
}
while ((chr = getc(filep)) != EOF)
{
if (first_read)
{first_read = FALSE;
if (chr == 0xf5)
fatal ("File %s is binary, can't process--ASCII req.",Filename);
}
if (SkipToEOL) goto REM_DATA; /* REM, DATA--skip to end of line*/
/* normal char - add to current word */
if ((chr <= 'z' && chr >= 'a') ||
(chr <= 'Z' && chr >= 'A') )
{
if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
inword++ ;
_listchr(chr) ;
}
else switch (chr)
{
/* These can't be 1st char in word -- */
/* digit, period, suffixes for variable type */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.': case '%': case '&': case '!': case '#': case '$':
if (inword)
{ if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
}
_listchr(chr) ;
break ;
/* newline - end current word */
case '\n':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
Hiline++ ;
break ;
/* Apostrophe (') comment - print & bypass */
/* to end of the line. */
case '\'':
if (inword)
_rtrnwrd(wp) ;
REM_DATA: /* Come here for REM & DATA keywords */
_listchr(chr) ;
while ((chr = getc(filep)) != EOF)
{ _listchr(chr);
if (chr == '\n')
{ Hiline++;
SkipToEOL = FALSE;
break;
}
}
if (chr == EOF) ungetc(chr, filep);
break ;
/* words in quotes - print & bypass */
case '"':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
while ((chr = getc(filep)) != EOF)
{ _listchr(chr);
if (chr == '"')
break;
if (chr == '\n') /* Making assumption here that */
{ Hiline++; /* end of line is implied end of*/
break; /* quote string. Apparently this*/
} /* is what AmigaBasic does. */
}
if (chr == EOF) ungetc(chr,filep);
break ;
default:
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
break ;
} /* End of switch -- process char's */
lastchr = chr ;
} /* End of while -- read char's */
if (inword)
_rtrnwrd(wp) ;
_listchr(EOF) ;
return NULL ;
}
/* listchr - list the input files one character at a time*/
static Listpage = 0 ;
static Listpline = MAXPAGLINES ;
listchr(chr)
register chr ;
{
static char linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
static lastchr=0, linecnt=0 ;
static int remain;
static int LNWid = 4; /* Line number width on listing */
/* Changed from 6 in CREF to 4 in BREF */
if (chr == -2) /* clear line buffer */
{ setmem(linebuf,Maxlinwidth,' ');
return;
}
if (chr == EOF) /* EOF - print final line */
{ *lineptr = '\0' ;
listline(linebuf) ;
Listpage = 0 ;
Listpline = MAXPAGLINES ;
lineptr = linebuf ;
linecnt = 0 ;
return ;
}
if (lineptr == linebuf) /* new line - format line number */
{ ltoc(linebuf, Hiline, LNWid) ;
lineptr = linebuf + LNWid ;
*lineptr++ = ' ' ;
*lineptr++ = ' ' ;
linecnt = LNWid + 2;
}
#define _lineoflo(ctr, newctr) \
if ((ctr) >= Maxlinwidth) \
{ *lineptr = '\0' ; \
listline(linebuf) ; \
lineptr = &linebuf[LNWid + 2] ; \
linecnt = (newctr) ; \
}
switch (chr)
{ /* newline - print last line */
case '\n':
if (lastchr != '\f')
{ *lineptr = '\0' ;
listline(linebuf) ;
}
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* formfeed - print line and end page*/
case '\f':
if (linecnt != LNWid + 2)
{ *lineptr = '\0' ;
listline(linebuf) ;
}
Listpline = MAXPAGLINES ; /* This triggers form feed*/
/* on next entry--listline*/
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* tab - skip to next tab stop */
case '\t':
linecnt += Tabsize ;
remain = linecnt % Tabsize ;
linecnt -= remain;
_lineoflo(linecnt, LNWid + 2) ;
lineptr += Tabsize ;
lineptr -= remain;
break ;
/* backspace - print, but don't count*/
case '\b':
*lineptr++ = chr ;
break ;
/* ctl-char - print as "^x" */
case 001: case 002: case 003:
case 004: case 005: case 006: case 007:
case 013:
case 015: case 016: case 017:
case 020: case 021: case 022: case 023:
case 024: case 025: case 026: case 027:
case 030: case 031: case 032: case 033:
case 034: case 035: case 036: case 037:
_lineoflo(linecnt+=2, LNWid + 4) ;
*lineptr++ = '^' ;
*lineptr++ = ('A'-1) + chr ;
break ;
default:
if (isprint(chr))
{ _lineoflo(++linecnt, LNWid + 3) ;
*lineptr++ = chr ;
}
else /* non-ascii chars - print as "\nnn" */
{ _lineoflo(linecnt+=4, LNWid + 6) ;
*lineptr++ = '\\' ;
*lineptr++ = '0' + ((chr & 0300) >> 6) ;
*lineptr++ = '0' + ((chr & 070) >> 3) ;
*lineptr++ = '0' + (chr & 07) ;
}
break ;
}
lastchr = chr ;
}
/* print a completed line from the input file */
listline(line)
register char *line ;
{
if (*line)
{ if (++Listpline >= (Maxpaglines-8))
{ if (FormFeed)
if (files >1 || Listpage) putchar('\f') ;
printf("\nBREF %s %s %s Page %d\n\n",
Version, Date, Filename, ++Listpage) ;
Listpline = 0 ;
}
puts(line) ;
listchr(-2); /* clear line buffer */
}
}
/* storword - store word and line # in binary word tree or word file*/
storword(word, lineno)
register char *word ;
long lineno ;
{
char lword[MAXWORD+1] ;
register char *cp1, *cp2 ;
WRDLIST *addword() ;
/* convert word to lower case */
for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
;
/* store words and lineno */
Wdtree = addword(Wdtree, word, lword, lineno) ;
}
/* addword - add word and line# to in-core word list*/
WRDLIST *
addword(wdp, word, lword, lineno)
register WRDLIST *wdp ;
char *word, *lword ;
long lineno ;
{
char *malloc() ;
int comp ;
/* insert new word into list */
if (wdp == NULL)
{ register wordlen = strlen(word) + 1 ;
wdp = (WRDLIST *)malloc((wordlen * 2)+sizeof(WRDLIST));
if (wdp == NULL)
goto nomemory ;
wdp->wd_wd = (char *)wdp + sizeof(WRDLIST) ;
wdp->wd_lwd = wdp->wd_wd + wordlen ;
strcpy(wdp->wd_wd, word) ;
strcpy(wdp->wd_lwd, lword) ;
wdp->wd_hi = wdp->wd_low = NULL ;
wdp->wd_ln.ln_no = lineno ;
wdp->wd_ln.ln_next = NULL ;
}
/* word matched in list? */
else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
&& ((comp = strcmp(word, wdp->wd_wd)) == 0))
{ register LINLIST *lnp, **lnpp ;
if (wdp->wd_ln.ln_no)
{ /* add line# to linked list*/
lnp = &wdp->wd_ln ;
do
{ if (lineno == lnp->ln_no)
return wdp ;
lnpp = &lnp->ln_next ;
} while ((lnp = *lnpp) != NULL) ;
*lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
if ((lnp = *lnpp) == NULL)
goto nomemory ;
lnp->ln_no = lineno ;
lnp->ln_next = NULL ;
}
}
else if (comp < 0) /* search for word in children */
wdp->wd_low = addword(wdp->wd_low, word, lword,lineno);
else
wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
return wdp ;
/* not enough memory - convert to -b */
nomemory:
fatal("not enough memory for in-core word list") ;
}
/* bref - print cross reference report from internal word list*/
#define MAXLNOS 2000 /* maximum line nos. for a word */
long Linenos[MAXLNOS] ; /* list of line numbers for a word */
bref(wdtree)
register WRDLIST *wdtree ;
{
if (Elite)
{printf ("%s","w"); /* Turn off elite for printer */
Maxlinwidth = SaveMLW; /* Restore original Max line width*/
}
breftree(wdtree) ;
if (FormFeed)
putchar ('\f'); /*Final form feed after print x-ref table*/
}
breftree(wdp) /* recursively print word tree nodes */
register WRDLIST *wdp ;
{
register LINLIST *lnp ;
register nos ;
if (wdp != NULL)
{ breftree(wdp->wd_low) ; /* print lower children */
nos = 0 ;
if (Linenos[0] = wdp->wd_ln.ln_no)
{ lnp = &wdp->wd_ln ;
while ((lnp = lnp->ln_next) != NULL)
if (nos < (MAXLNOS-2))
Linenos[++nos] = lnp->ln_no ;
printword(wdp->wd_wd, nos) ;
}
breftree(wdp->wd_hi) ; /* print higher children */
}
}
/* printword - print a word and all its line number references*/
printword(word, nos)
char *word ;
register nos ;
{
static firstime=TRUE, linecnt, maxlnos, lnosize ;
register cnt ;
if (firstime)
{ firstime = FALSE ;
linecnt = Maxpaglines ;
for (lnosize=1 ; Hiline ; lnosize++)
Hiline /= 10L ;
maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
}
if (linecnt >= (Maxpaglines - 5))
{ printheads() ;
linecnt = 5 ;
}
printf("%-15s%5d ", word, ++nos) ;
Linenos[nos] = 0 ;
for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
{ if (++cnt > maxlnos)
{ cnt = 1 ;
if (linecnt++ >= (Maxpaglines - 4))
{ printheads() ;
linecnt = 5 ;
printf("%-15s(cont) ", word);
}
else
printf("\n%22s", " ") ;
}
printf("%*ld", lnosize, Linenos[nos]) ;
}
putchar('\n') ;
linecnt++ ;
}
/* printheads - print page headings*/
printheads()
{
static page=0 ;
long time() ;
if (!page)
mkdate(time( (long *)0)) ;
if (FormFeed) putchar('\f') ; /* Form feed */
printf("\nBREF %s %s %.*s Page %d\n\n",
Version, Date, (Maxlinwidth-36), Brefhdr, ++page) ;
printf("word refs line numbers\n\n") ;
}
/* ltoc - store ASCII equivalent of long value in given field*/
ltoc(fld, lval, len)
register char *fld ;
register long lval ;
register len ;
{
fld += len ;
while (len-->0)
if (lval)
{ *--fld = '0' + (lval%10L) ;
lval /= 10L ;
}
else
*--fld = ' ' ;
}
/* mkdate - build time/date for use in heading lines*/
mkdate(atime)
long atime ;
{
long mtime ;
char *cp, *ctime() ;
debug("MKDATE(%ld)\n", atime) ;
mtime = atime ;
cp = ctime(&mtime) ;
*(cp+24) = ' ' ; /* clear newline */
strcpy(cp+16, cp+19) ; /* shift over seconds */
strcpy(Date, cp+4) ;
}
/* strjoin - join "str1" to "str2" (separated by "sep")
* Truncate if necessary to "max" chars.*/
strjoin(str1, sep, str2, max)
register char *str1, *str2;
char sep ;
register max ;
{
if (*str2)
{ if (*str1)
{ while (*str1++)
if (--max <= 0)
goto oflo ;
max--, str1-- ;
*str1++ = sep ;
}
while (*str1++ = *str2++)
if (--max <= 0)
goto oflo ;
}
return ;
oflo:
*--str1 = '\0' ;
return ;
}
/* fatal - print standard error msg and halt process*/
fatal(ptrn, data1, data2)
register char *ptrn, *data1, *data2 ;
{
fprintf(stderr, "%s: ", Progname) ;
fprintf(stderr, ptrn, data1, data2) ;
putc('\n', stderr) ;
exit(1);
}